#include <Arduino.h>

// 用于指定设备接入方式:WiFi接入
#define BLINKER_WIFI
// 语音助手接入-小爱设备配置-插座(outlet)
#define BLINKER_MIOT_OUTLET
#define BLINKER_APCONFIG
#define BLINKER_OTA_VERSION_CODE "0.1.3"
#include <ArduinoJson.h>
#include <Blinker.h>
#include <common/time/time.h>
#include <common/config/config.h>
#include <common/wifi/wifi.h>
#include <common/json/json.h>
#include <hardware/motor/motor.h>
#include <hardware/bl0942/bl0942.h>

void setCurrent();
void setVoltage();
void setPower();
void setElectricity();

String apIp = "";
// 新建重置按钮组件对象/绑定组件
BlinkerButton ResetButton((char *)"reset-btn");
// 重置按钮组件回调函数
void deviceReset(const String &state)
{
  // Reset device ,erase WiFi config.
  Blinker.reset();
}
// 新建按钮组件对象/绑定组件
BlinkerButton ApButton((char *)"open-ap-btn");
BlinkerText ApIpText((char *)"ap-ip-tex");
// 组件回调函数
// 在回调函数中, state 的值为:开关 : "on"(打开); "off"(关闭)
void ap_button_callback(const String &state)
{
  apIp = createWebserver();
  Blinker.print("mac", initEspnow());
  needOTA = 1;
  ApIpText.print("ap ip", apIp);
}

// 新建按钮组件对象/绑定组件
BlinkerButton GetInfoButton((char *)"get-info-btn");
//回调函数例子
StaticJsonDocument<1024> readChipCallback(StaticJsonDocument<1024> doc)
{
  int8_t sec = Blinker.second();
  int8_t min = Blinker.minute();
  int8_t hour = Blinker.hour();
  int8_t mday = Blinker.mday();
  int8_t month = Blinker.month();
  int16_t year = Blinker.year();
  doc["serverTime"] = getFormattedTime(year, month, mday, hour, min, sec);
  return doc;
}
// 组件回调函数
// 在回调函数中, state 的值为:开关 : "on"(打开); "off"(关闭)
void get_info_button_callback(const String &state)
{
  String json = readChip();
  Blinker.print("json", json);
  //验证回到函数的使用
  StaticJsonDocument<1024> doc = jsonToDoc(json, readChipCallback);
  Blinker.print("bl0942", docToJson(doc));
}
// 新建按钮组件对象/绑定组件
BlinkerButton NTPButton((char *)"ntp-btn");
BlinkerText NTPtimeText((char *)"ntp-time-tex");
BlinkerText NTPRuntimeText((char *)"ntp-runtime-tex");
// 组件回调函数
// 在回调函数中, state 的值为:开关 : "on"(打开); "off"(关闭)
void ntp_button_callback(const String &state)
{
  int8_t sec = Blinker.second();
  int8_t min = Blinker.minute();
  int8_t hour = Blinker.hour();
  int8_t mday = Blinker.mday();
  int8_t month = Blinker.month();
  int16_t year = Blinker.year();
  time_t run_time = Blinker.runTime();
  NTPtimeText.print("当前时间", getFormattedTime(year, month, mday, hour, min, sec));
  NTPRuntimeText.print("运行时间", getFormattedTime(run_time));
}
// 新建按钮组件对象/绑定组件
BlinkerButton MotorButton((char *)"motor-btn");
// 组件回调函数
// 在回调函数中, state 的值为:开关 : "on"(打开); "off"(关闭)
void motor_button_callback(const String &state)
{
  BLINKER_LOG("get button state: ", state);
  BLINKER_LOG("getStatusForForward: ", getStatusForForward());
  BLINKER_LOG("getStatusForReverse: ", getStatusForReverse());
  if (state == BLINKER_CMD_ON)
  {
    //低电平正转，高电平反转
    tickerMotor(0);
    MotorButton.color("#FF0000");
    // 设置按键中显示的名字或者描述
    MotorButton.text("正转");
    // 发送按键当前的状态(多用于开关模式下反馈开关状态), 并将以上设置一并发送到APP
    MotorButton.print(BLINKER_CMD_ON);
  }
  else
  {
    //低电平正转，高电平反转
    tickerMotor(1);
    MotorButton.color("#808080");
    MotorButton.text("反转");
    MotorButton.print(BLINKER_CMD_OFF);
  }
  // 特定指令-使用Blinker.vibrate()即会让手机震动
  Blinker.vibrate();
}
// 小爱电源类操作的回调函数:
// 当小爱同学向设备发起控制, 设备端需要有对应控制处理函数
// 务必在回调函数中反馈该控制状态:BlinkerMIOT.powerState
// 在回调函数中, state 的值为:开关 : "on"(打开); "off"(关闭)
void miotPowerState(const String &state)
{
  BLINKER_LOG("need set power state: ", state);
  if (state == BLINKER_CMD_ON)
  {
    //低电平正转，高电平反转
    tickerMotor(0);
    MotorButton.color("#FF0000");
    // 设置按键中显示的名字或者描述
    MotorButton.text("正转");
    // 发送按键当前的状态(多用于开关模式下反馈开关状态), 并将以上设置一并发送到APP
    MotorButton.print(BLINKER_CMD_ON);
    // 反馈电源状态
    BlinkerMIOT.powerState(BLINKER_CMD_ON);
    // 将以上属性发送出去, 务必最后调用该函数
    BlinkerMIOT.print();
  }
  else if (state == BLINKER_CMD_OFF)
  {
    //低电平正转，高电平反转
    tickerMotor(1);
    MotorButton.color("#808080");
    MotorButton.text("反转");
    MotorButton.print(BLINKER_CMD_OFF);
    BlinkerMIOT.powerState(BLINKER_CMD_OFF);
    BlinkerMIOT.print();
  }
}
//数据组件
//1.如果启用实时数据，需要Blinker.attachRTData(rtData);注册实时回调函数rtData
//2.如果没有启动实时数据，需要通过输入框调用dataRead回调函数，在此函数里面设置P1Number
BlinkerNumber C1Number((char *)"num-c1");
BlinkerNumber V1Number((char *)"num-v1");
BlinkerNumber P1Number((char *)"num-p1");
BlinkerNumber E1Number((char *)"num-e1");
// 读取数据的回调函数
//在点灯科技app中增加输入框，这个回调函数可以接受输入框的数据
void dataRead(const String &data)
{
  //BLINKER_LOG("Blinker readString: ", data);
  // 如使用Blinker.vibrate()即会让手机震动。
  Blinker.vibrate();
  if(strcmp(data.c_str(), "c") ==0)
  {
    setCurrent();
  }
  if(strcmp(data.c_str(), "v") ==0)
  {
    setVoltage();
  }
  if(strcmp(data.c_str(), "p") ==0)
  {
    setPower();
  }
  if(strcmp(data.c_str(), "e") ==0)
  {
    setElectricity();
  }
  if(strcmp(data.c_str(), "all") ==0)
  {
    setCurrent();
    setVoltage();
    setPower();
    setElectricity();
  }
  uint32_t BlinkerTime = millis();
  // 使用print可以向app发送数据,数据键名对应app上的组件名称
  Blinker.print("millis", BlinkerTime);
}
void setCurrent()
{
  C1Number.icon("icon_1");
  C1Number.color("#FFFFFF");
  C1Number.unit("A");
  C1Number.print(getValueByKey("C1").toFloat());
}
void setVoltage()
{
  V1Number.icon("icon_1");
  V1Number.color("#FFFFFF");
  V1Number.unit("V");
  V1Number.print(getValueByKey("V1").toFloat());
}
void setPower()
{
  P1Number.icon("icon_1");
  P1Number.color("#FFFFFF");
  P1Number.unit("W");
  P1Number.print(getValueByKey("P1").toFloat());
}
void setElectricity()
{
  E1Number.icon("icon_1");
  E1Number.color("#FFFFFF");
  E1Number.unit("kWh");
  E1Number.print(getValueByKey("E1").toFloat());
}
// void rtData()
// {
//     Blinker.sendRtData((char *)"num-v1", getValueByKey("V1"));
//     Blinker.printRtData();
// }
void setup()
{
  // 初始化串口，仅调试用，如果串口用于和其他外设通信，一定要关闭调试
  Serial.begin(115200, SERIAL_8N1, SERIAL_FULL);
  // 开启调试信息,用于指定调试信息输出的串口，设备开发时调试使用，项目或产品成型后，可以删除不用
  // 如果串口用于和其他外设通信，一定要关闭调试
  BLINKER_DEBUG.stream(Serial);
  // 初始化继电器
  initMotor();
  // 初始化按键
  initSwitch();
  // 初始化blinker
  // Blinker.begin(auth, ssid, pswd);
  Blinker.begin(auth);

  // 初始化NTP
  Blinker.setTimezone(8.0);

  ApIpText.print("ap ip", apIp);
  
  ResetButton.attach(deviceReset);
  // 注册组件回调函数
  MotorButton.attach(motor_button_callback);
  // 注册组件回调函数
  ApButton.attach(ap_button_callback);
  GetInfoButton.attach(get_info_button_callback);
  NTPButton.attach(ntp_button_callback);
  // 注册该回调函数
  Blinker.attachData(dataRead);
  //Blinker.attachRTData(rtData);
  // 小爱同学务必在回调函数中反馈该控制状态
  // 注册回调函数
  BlinkerMIOT.attachPowerState(miotPowerState);
  // 初始化BL0942
  //initBl0942();
}
void loop()
{
  // put your main code here, to run repeatedly:
  // Blinker.run()语句负责处理Blinker收到的数据，每次运行都会将设备收到的数据进行一次解析。
  // 在使用WiFi接入时，该语句也负责保持网络连接
  Blinker.run();
  // 检查http服务器访问
  handleClient();
}